#! usr/bin/env python3
# -*- coding: utf-8 -*-
import hashlib
import random
import sys
from Crypto.PublicKey import ECC
from gmpy2 import mpz, is_prime, random_state, mpz_urandomb, mpz_random, powmod, bit_length, mul, invert, t_mod, \
    next_prime, f_div

rand = random_state(random.randrange(sys.maxsize))
P=0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551
G=ECC.EccPoint(0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296,0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5)
#来自于secp256r1的G。
class KGC(object):
    def __init__(self):
        self.createk()

    def createk(self):
        key = ECC.generate(curve='P-256')
        self.pk = key.public_key().pointQ
        self.sk=  key.d


class Params(object):
    def __init__(self, pa, pb):
        self.pa = pa
        self.pb = pb

# user key class
class User(object):

    def __init__(self,uid,pk):
        self.pk = pk
        self.id = str(H1_hash(uid, pk,pk))

        # signcryption function

    def signcrypt(self, Reciever, params, m, sk):
        w = mpz_urandomb(rand,255)
        h1 =H1_hash(self.id, Reciever.id, w)
        C=m*w
        t = self.T(w, Reciever.pk)
        h2=H2_hash(self.id,C,m,h1)
        s=self.S(h2,sk)
        return (h1,t,C,s)

    def unsigncrypt(self, Sender, Signcryption_text,sk):
        h1 = Signcryption_text[0]
        t = Signcryption_text[1]
        c = Signcryption_text[2]
        s = Signcryption_text[3]
        #print(t[0].x)
        t2=sk * (t[0])
        w=t[1]-t2.x
        m=f_div(c,mpz(w))
        h1v=H1_hash(Sender.id, self.id, w)
        h2=H2_hash(Sender.id,c,m,h1)
        vh2=self.Vh(h2,s[0],s[1],Sender.pk)
        #print(s[0])
        #print("rG:",s[0]*G)
        if vh2==s[0]*G and h1v==h1:
            return m
        else:
            return False

    def T(self, w, pk):
        r=int(mpz_urandomb(rand,255))
        t1=r*G
        t2=pk*r
        t2=t2.x+w
        return (t1,t2)

    def S(self,h2,ska):
        r = mpz_urandomb(rand, 255)
        s1=r*G
        #print("rG1:",s1)
        h1=H1_hash(str(h2),s1.x,s1.y)
        #print("h1:",h1)
        print(ska)
        print(type(ska))
        a=mpz(ska)
        print(a)
        print(type(a))
        s=powmod(r-h1*mpz(ska),1,P)
        #print("s:",s)
        return (r,s)

    def Vh(self, h, r,s,pk):
        print(s)
        a=s*G
        rG=r*G
        b=H1_hash(str(h),rG.x,rG.y)
        #print("h1:",b)
        c=b*pk
        d=a+c
        #print(d)
        return d


def hash_func(x):
    temp1 = hashlib.sha512()
    temp2 = hashlib.sha512()
    temp3 = hashlib.sha512()
    temp4 = hashlib.sha512()
    temp1.update(x + b"1")
    temp2.update(x + b"2")
    temp3.update(x + b"3")
    temp4.update(x + b"4")
    ret_str = temp1.hexdigest() + temp2.hexdigest() + temp3.hexdigest() + temp4.hexdigest()
    return ret_str


# define the H1 hashfunction
def H1_hash(uid, x, y):
    temp = hash_func(uid.encode('utf-8') + str(x).encode('utf-8') + str(y).encode('utf-8'))
    H1_hash_value = mpz(temp[: 126], 16)
    return H1_hash_value


# define the H2 hashfunction
def H2_hash(uid, x, y, z):
    temp = hash_func(uid.encode('utf-8') + str(x).encode('utf-8') + str(y).encode('utf-8') + str(z).encode('utf-8'))
    H2_hash_value = mpz(temp[:126], 16)
    return H2_hash_value


# define the H3 hashfunction
def H3_hash(x):
    temp = hash_func(str(x).encode('utf-8'))
    H3_hash_value = mpz(temp[: 126], 16)
    return H3_hash_value


if __name__ == "__main__":
    alicedone=KGC()
    bobdone=KGC()
    params = Params(alicedone.pk, bobdone.pk)
    alice = User("Alice", alicedone.pk)
    bob = User("Bob", bobdone.pk)
    m = mpz(2 ** 16)
    Signcryption_text = alice.signcrypt(bob, params, m, alicedone.sk)
    print(Signcryption_text)
    m=bob.unsigncrypt(alice,Signcryption_text,bobdone.sk)
    print(m)
    #print(b)
